package cn.edu.cimv.util;

import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 加密解密相关
 * RSA用公钥加密，私钥解密
 *
 */
public class CryptionUtil {
    private static final Logger logger = LoggerFactory.getLogger(CryptionUtil.class);
    private static Properties properties = null;
    public static final String KEY_ALGORITHM = "RSA";
    private static final String PUBLIC_KEY = "RSAPublicKey";
    private static final String PRIVATE_KEY = "RSAPrivateKey";
    // 读取预置信息
    static {
        Resource resource = new ClassPathResource("properties/rsa.properties");
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");

        try {
            properties = PropertiesLoaderUtils.loadProperties(encodedResource.getResource());
        } catch (IOException e) {
            logger.error(" 配置文件读取失败#errMsg: " + e.getMessage(), e);
        }
    }
    /**
     * 加密<br>
     * 用公钥加密
     * @param inputStr
     * @return
     * @throws Exception
     */
    public static String encryptByPublicKey( String inputStr )
            throws Exception {
        byte[] data = inputStr.getBytes();
        //读取公钥
         String key = properties.getProperty("publicKey");
        // 对公钥解密
        byte[] keyBytes = decryptBASE64(key);
        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        String outputStr = encryptBASE64(cipher.doFinal(data));
        return outputStr;
    }

    /**
     * 加密<br>
     * 用私钥加密
     * @param inputStr
     * @return
     * @throws Exception
     */
    public static String encryptByPrivateKey( String inputStr )
            throws Exception {
        byte[] data = inputStr.getBytes();
        //读取私钥
         String key = properties.getProperty("privateKey");
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        String outputStr = encryptBASE64(cipher.doFinal(data));
        return outputStr;
    }
    /**
     * 解密<br>
     * 用私钥解密
     * @param  inputStr
     * @return
     * @throws Exception
     */
    public static String decryptByPrivateKey( String inputStr )
            throws Exception {
        byte[] data = decryptBASE64(inputStr);
        //读取私钥
        String key = properties.getProperty("privateKey");
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        String outputStr = new String(cipher.doFinal(data));
        return outputStr;
    }

    /** *//**
     * 解密<br>
     * 用公钥解密
     * @param  inputStr
     * @return
     * @throws Exception
     */
    public static  String  decryptByPublicKey( String inputStr )
            throws Exception {
        byte[] data = decryptBASE64(inputStr);
        //读取公钥
        String key = properties.getProperty("publicKey");
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);

        // 取得公钥
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicKey = keyFactory.generatePublic(x509KeySpec);

        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        String outputStr = new String(cipher.doFinal(data));
        return outputStr;
    }

    /**
     * 取得私钥
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap)
            throws Exception {
        Key key = (Key) keyMap.get(PRIVATE_KEY);

        return encryptBASE64(key.getEncoded());
    }

    /**
     * 取得公钥
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap)
            throws Exception {
        Key key = (Key) keyMap.get(PUBLIC_KEY);

        return encryptBASE64(key.getEncoded());
    }

    /**
     * 初始化密钥
     * @return
     * @throws Exception
     */
    public static Map<String, Object> initKey() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator
                .getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // 私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
    /**
     * BASE64解密
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * BASE64加密
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key) throws Exception {
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    /**
     * url密码加密
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptURL(byte[] key) throws Exception {
        //在base64前面加上一个随机数
        String myencrypt = String.valueOf((int)(Math.random() * 10)).substring(0,1);
        String urlencrypt = myencrypt + (new BASE64Encoder()).encodeBuffer(key);
        return urlencrypt;
    }
    /**
     * url密码解密
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptURL(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key.substring(1,key.length()));
    }

    /**
     * 将传入的字符串进行MD5加密
     * @param str
     * @return
     */
    public static String toMd5(String str) {
        return Hashing.md5().hashString(str, Charsets.UTF_8).toString();
    }
}
